#include "Protocol.hpp"
#include "Socket.hpp"

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

using namespace Protocol;

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cout << "Usage: " << " serverip serverport" << std::endl;
        return 1;
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);
    // 创建套接字
    Net_Work::Socket *conn = new Net_Work::TcpSocket();

    if (!conn->BuildConnectSocketMethod(serverip, serverport))
    {
        std::cerr << "connect " << serverip << ":" << serverport << " failed" << std::endl;
    }
    std::cout << "connect " << serverip << ":" << serverport << " success" << std::endl;

    // 使用工厂模式
    std::unique_ptr<Protocol::Factory> factory = std::make_unique<Protocol::Factory>();
    srand(time(nullptr) ^ getpid()); // 建立随机数的种子
    const std::string opers = "+-*/%";
    while (true)
    {
        // 构建请求，遵守协议
        int x = rand() % 100; // [0, 99)
        usleep(rand() % 1234);
        int y = rand() % 100; // [0, 99)
        char op = opers[rand() % opers.size()];
        // 创建请求
        std::shared_ptr<Protocol::Request> req = factory->BuildRequest(x, y, op);
        // 对请求序列化
        std::string request_str;
        req->Serialize(&request_str);
        std::cout << request_str << std::endl;

        // for test
        std::string testreq = request_str;
        testreq += " ";
        testreq += "= ";

        // 添加报头
        request_str = Encode(request_str);
        // 发送请求
        conn->Send(request_str);
        
        std::string response_str;
        while(true)
        {
            // 读取响应
            if(!conn->Recv(&response_str, 1024)) break;
            // 解析响应报文
            std::string response;
            if(!Decode(response_str, &response))
                continue;
            // 反序列化
            auto resp = factory->BuildResponse();
            resp->Deserialize(response);
            // 得到了结果
            std::cout << testreq << resp->GetResult() << "[" << resp->GetCode() << "]" << std::endl;

            break;
        }
        sleep(1);
    }
    

    conn->CloseSocket();
    return 0;
}